
#include "CDirectInput.h"

#ifndef DIERRBOX
	#define DIERRBOX(hWnd, errorText)	{ MessageBox(hWnd, errorText, "CDirectInput Error", MB_OK | MB_ICONEXCLAMATION); }
#endif

CDirectInput CDirectInput::m_Instance;

CDirectInput::CDirectInput(void)
{
	m_lpDIObject	= NULL;
	m_pKeyboard		= NULL;
	m_pMouse		= NULL;

}

CDirectInput::~CDirectInput(void)
{
	ShutdownDirectInput();
}
CDirectInput* CDirectInput::GetInstance(void)
{
	return &m_Instance;
}
bool CDirectInput::InitDirectInput(HWND hWnd, HINSTANCE hInstance, unsigned int unInitDevices, unsigned int unExclusiveDevices)
{
	//	Create the DirectInput Object
	if (FAILED( DirectInput8Create(hInstance, DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&m_lpDIObject, NULL) ))
		return false;

	//	Initialize the keyboard if the keyboard flag is on
	if (unInitDevices & DI_KEYBOARD)
	{
		//	Initialize the keyboard
		if (!InitKeyboard(hWnd, (unExclusiveDevices & DI_KEYBOARD) ? true : false ))
			return false;
	}

	//	Initialize the mouse if the mouse flag is on
	if (unInitDevices & DI_MOUSE)
	{
		//	Initialize the mouse
		if (!InitMouse(hWnd, (unExclusiveDevices & DI_MOUSE) ? true : false ))
			return false;
	}

	//	Return success.
	return true;
}
void CDirectInput::ShutdownDirectInput(void)
{
	UnacquireAll();

	if (m_pKeyboard)
	{
		if (m_pKeyboard)
		{
			delete m_pKeyboard;
			m_pKeyboard = NULL;
		}
	}

	if (m_pMouse)
	{
		if (m_pMouse)
		{
			delete m_pMouse;
			m_pMouse = NULL;
		}
	}
}

void CDirectInput::ReadDevices(void)
{
	if (m_pKeyboard)
	{
		m_pKeyboard->ReadDevice();
		m_pKeyboard->ReadBufferedDevice();
	}

	if (m_pMouse)
	{
		m_pMouse->ReadDevice();
		m_pMouse->ReadBufferedDevice();
	}
	
}

///////////////////////////////////////////////////////////////////
//	Function:	"ClearInput"
//
//	Last Modified:		9/30/2009
//
//	Input	:	void
//
//	Return	:	void
//
//	Purpose	:	Clears out the input for all the initialized devices.
///////////////////////////////////////////////////////////////////	
void CDirectInput::ClearInput(void)
{
	if (m_pKeyboard)
	{
		m_pKeyboard->ClearKeys();
	}

	if (m_pMouse)
	{
		m_pMouse->ClearMouseButtons();
	}

}

void CDirectInput::AcquireAll(void)
{
	if (m_pKeyboard)
		m_pKeyboard->Acquire();

	if (m_pMouse)
		m_pMouse->Acquire();
}

void CDirectInput::UnacquireAll(void)
{
	if (m_pKeyboard)
		m_pKeyboard->Unacquire();

	if (m_pMouse)
		m_pMouse->Unacquire();
}


bool CDirectInput::InitKeyboard(HWND hWnd, bool bIsExclusive)
{
	//	Make sure we aren't trying to do this a second time.
	if (m_pKeyboard)
	{
		DIERRBOX(hWnd, "Keyboard has already been initialized")
		return false;
	}

	m_pKeyboard = new CDIKeyboard(m_lpDIObject, hWnd, bIsExclusive);
	
	if (m_pKeyboard == NULL)
		return false;

	return true;
}


bool CDirectInput::KeyDown(unsigned char ucDIKey)			{ return (m_pKeyboard && m_pKeyboard->KeyDown(ucDIKey)); }
bool CDirectInput::KeyPressed(unsigned char ucDIKey)		{ return (m_pKeyboard && m_pKeyboard->KeyPressed(ucDIKey)); }
bool CDirectInput::KeyPressedEx(unsigned char ucDIKey)		{ return (m_pKeyboard && m_pKeyboard->KeyPressedEx(ucDIKey)); }
bool CDirectInput::KeyUp(unsigned char ucDIKey)			{ return (m_pKeyboard && m_pKeyboard->KeyUp(ucDIKey)); }
bool CDirectInput::KeyReleased(unsigned char ucDIKey)		{ return (m_pKeyboard && m_pKeyboard->KeyReleased(ucDIKey)); }
bool CDirectInput::KeyReleasedEx(unsigned char ucDIKey)	{ return (m_pKeyboard && m_pKeyboard->KeyReleasedEx(ucDIKey)); }
char CDirectInput::CheckKeys(void)					{ return (m_pKeyboard) ? m_pKeyboard->CheckKeys() : 0; }
char CDirectInput::CheckBufferedKeysEx(void)			{ return (m_pKeyboard) ? m_pKeyboard->CheckBufferedKeysEx() : 0; }
unsigned char CDirectInput::GetDIKCode(void)			{ return (m_pKeyboard) ? m_pKeyboard->GetDIKCode() : 0; }
unsigned char CDirectInput::GetBufferedDIKCodeEx(void)	{ return (m_pKeyboard) ? m_pKeyboard->GetBufferedDIKCodeEx() : 0; }
bool CDirectInput::InitMouse(HWND hWnd, bool bIsExclusive)
{
	//	Make sure we aren't trying to do this a second time.
	if (m_pMouse)
	{
		DIERRBOX(hWnd, "Mouse has already been initialized")
		return false;
	}

	m_pMouse = new CDIMouse(m_lpDIObject, hWnd, bIsExclusive);
	
	if (m_pMouse == NULL)
		return false;

	return true;
}
bool CDirectInput::MouseButtonDown(unsigned char ucButton)			{ return (m_pMouse && m_pMouse->ButtonDown(ucButton)); }
bool CDirectInput::MouseButtonPressed(unsigned char ucButton)		{ return (m_pMouse && m_pMouse->ButtonPressed(ucButton)); }
bool CDirectInput::MouseButtonPressedEx(unsigned char ucButton)	{ return (m_pMouse && m_pMouse->ButtonPressedEx(ucButton)); }
bool CDirectInput::MouseButtonUp(unsigned char ucButton)			{ return (m_pMouse && m_pMouse->ButtonUp(ucButton)); }
bool CDirectInput::MouseButtonReleased(unsigned char ucButton)		{ return (m_pMouse && m_pMouse->ButtonReleased(ucButton)); }
bool CDirectInput::MouseButtonReleasedEx(unsigned char ucButton)	{ return (m_pMouse && m_pMouse->ButtonReleasedEx(ucButton)); }
int CDirectInput::MouseCheckBufferedButtons(void)			{ return (m_pMouse) ? m_pMouse->CheckBufferedButtons() : -1; }
int CDirectInput::MouseCheckBufferedButtonsEx(void)			{ return (m_pMouse) ? m_pMouse->CheckBufferedButtonsEx() : -1; }
long CDirectInput::MouseMovementX(void)						{ return (m_pMouse) ? m_pMouse->MovementX() : 0; }
long CDirectInput::MouseMovementY(void)						{ return (m_pMouse) ? m_pMouse->MovementY() : 0; }
long CDirectInput::MouseWheelMovement(void)					{ return (m_pMouse) ? m_pMouse->WheelMovement() : 0; }
int CDirectInput::MouseGetNumButtons(void)			{ return (m_pMouse) ? m_pMouse->GetNumButtons() : 0; }
int CDirectInput::MouseGetPosX(void)			{ return (m_pMouse) ? m_pMouse->GetPosX() : 0; }
int CDirectInput::MouseGetPosY(void)			{ return (m_pMouse) ? m_pMouse->GetPosY() : 0; }
void CDirectInput::MouseSetPosX(int nPosX)			{ if (m_pMouse) m_pMouse->SetPosX( nPosX ); }
void CDirectInput::MouseSetPosY(int nPosY)			{ if (m_pMouse) m_pMouse->SetPosY( nPosY ); }


//////////////////////////////////////////////////////////////////////////////////
//	CSGD_DIKeyboard
//////////////////////////////////////////////////////////////////////////////////

CDIKeyboard::CDIKeyboard(LPDIRECTINPUT8 pDI, HWND hWnd, bool bIsExclusive)
{
	//	Create the Keyboard Device.
	if (FAILED( pDI->CreateDevice(GUID_SysKeyboard, &m_lpDevice, NULL) ))
	{
		DIERRBOX(hWnd, "Failed to create Keyboard device.")
	}

	//	Set the Data Format for the Keyboard.
	if (FAILED( m_lpDevice->SetDataFormat(&c_dfDIKeyboard) ))
	{
		DIERRBOX(hWnd, "Failed to set data format on Keyboard.")
	}

	//	Set the Cooperative level for the keyboard.
	DWORD dwFlags = DISCL_FOREGROUND;

	if (bIsExclusive)
		dwFlags |= DISCL_EXCLUSIVE;
	else
		dwFlags |= DISCL_NONEXCLUSIVE | DISCL_NOWINKEY;

	if (FAILED( m_lpDevice->SetCooperativeLevel(hWnd, dwFlags) ))
	{
		DIERRBOX(hWnd, "Failed to set cooperative level on Keyboard.")
	}

	//	Set up the device to use buffered input
	//	For Use With Buffered Input.
	DIPROPDWORD dipdw;

	//	Clear the structure to all zeroes.
	memset(&dipdw, 0, sizeof(dipdw));

	dipdw.diph.dwSize       = sizeof(DIPROPDWORD);
	dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
	dipdw.diph.dwObj        = 0;
	dipdw.diph.dwHow        = DIPH_DEVICE;
	dipdw.dwData            = g_knBUFFER_SIZE;	//	Arbitrary buffer size

	//	Set the buffer size on the device.
	if (FAILED( m_lpDevice->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph) ))
		DIERRBOX(hWnd, "Could not Set the Properties for Buffered Input for Keyboard.");

	//	Acquire the Keyboard.
	if (FAILED( m_lpDevice->Acquire() ))
	{
		DIERRBOX(hWnd, "Failed to acquire Keyboard.")
	}	

	ClearKeys();

	//	Get the Keyboard Layout.
	m_keyLayout = GetKeyboardLayout(0);
}

///////////////////////////////////////////////////////////////////
//	Return	:	true if it can read the device state, false if it can't.
//	Purpose	:	Reads the state of the device every frame.
bool CDIKeyboard::ReadDevice(void)
{
	//	Make sure the keyboard device was made.
	if (!m_lpDevice)
		return false;

	//	Remember previously pressed keys
	memcpy(m_ucPrevKeysPressed, m_ucKeysPressed, sizeof(m_ucPrevKeysPressed));

	//	Attempt to read the keyboard...
	if (FAILED( m_lpDevice->GetDeviceState(sizeof(m_ucKeysPressed), (LPVOID)m_ucKeysPressed) ))
	{
		//	If we couldn't, try to re-acquire the device.
		if (FAILED( m_lpDevice->Acquire() ))
			return false; //	Could not re-acquire the Keyboard.

		//	Now try reading it
		if (FAILED( m_lpDevice->GetDeviceState(sizeof(m_ucKeysPressed), (LPVOID)m_ucKeysPressed) ))
			return false;
	}

	//	Success.
	return true;
}

///////////////////////////////////////////////////////////////////
//	Return	:	true if it can read the device state, false if it can't.
//	Purpose	:	Gets the DirectInput Buffered Data.
//	NOTE	:	For use with all Ex functions.
bool CDIKeyboard::ReadBufferedDevice(void)
{
	//	Make sure the device was made.
	if (!m_lpDevice)
		return false;

	ClearBufferedData();

	//	Attempt to read the device...
	if (FAILED( m_lpDevice->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), m_didod, &m_dwBufferElements, 0) ))
	{
		//	If we couldn't, try to re-acquire the device.
		if (FAILED( m_lpDevice->Acquire() ))
			return false; //	Could not re-acquire the Device.

		ClearBufferedData();

		//	Now try reading it
		if (FAILED( m_lpDevice->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), m_didod, &m_dwBufferElements, 0) ))
			return false;
	}

	//	Success.
	return true;
}

bool CDIKeyboard::KeyDown(unsigned char ucDIKey)
{
	//	if the high bit is on, it is pressed.
	return (m_ucKeysPressed[ucDIKey] & 0x80) ? true : false;
}

///////////////////////////////////////////////////////////////////
//	Input	:	ucDIKey	-	The DirectInput Keyboard Constant to check, such as DIK_ESCAPE.
//	Return	:	true if Key was pressed this frame.
//	Purpose	:	To tell if a key was just pressed (without using DirectInput's Buffered Input).
bool CDIKeyboard::KeyPressed(unsigned char ucDIKey)
{
	//	if the key is down and wasn't previously pressed.
	return KeyDown(ucDIKey) && !(m_ucPrevKeysPressed[ucDIKey] & 0x80);
}

///////////////////////////////////////////////////////////////////
//	Input	:	ucDIKey	-	The DirectInput Keyboard Constant to check, such as DIK_ESCAPE.
//	Return	:	true if the Key was pressed this frame.
//	Purpose	:	To tell if a key was just pressed (using DirectInput's Buffered Input).
bool CDIKeyboard::KeyPressedEx(unsigned char ucDIKey)
{
	//	Go through each element in the Buffer.
	for (DWORD i = 0; i < m_dwBufferElements; i++)
	{
		//	If the offset matches the key we are looking for and the high bit is on, it is pressed.
		if ((m_didod[i].dwOfs == ucDIKey) && (m_didod[i].dwData & 0x80))
			return true;
	}

	//	wasn't pressed.
	return false;
}


bool CDIKeyboard::KeyUp(unsigned char ucDIKey)
{
	//	if the high bit is off, it isn't pressed.
	return !KeyDown(ucDIKey);
}

///////////////////////////////////////////////////////////////////
//	Input	:	ucDIKey	-	The DirectInput Keyboard Constant to check, such as DIK_ESCAPE.
//	Return	:	true if the Key was released this frame.
//	Purpose	:	To tell if a key was just released (without using DirectInput's Buffered Input).
bool CDIKeyboard::KeyReleased(unsigned char ucDIKey) // was key just released?
{
	//	if the key is up and was previously pressed.
	return KeyUp(ucDIKey) && (m_ucPrevKeysPressed[ucDIKey] & 0x80);
}

///////////////////////////////////////////////////////////////////
//	Input	:	ucDIKey	-	The DirectInput Keyboard Constant to check, such as DIK_ESCAPE.
//	Return	:	true if the Key was released this frame.
//	Purpose	:	To tell if a key was just released (using DirectInput's Buffered Input).
bool CDIKeyboard::KeyReleasedEx(unsigned char ucDIKey) // uses DirectX Buffered Input
{
	//	Go through each element in the Buffer.
	for (DWORD i = 0; i < m_dwBufferElements; i++)
	{
		//	If the offset matches the key we are looking for and the high bit is off, it was released.
		if ((m_didod[i].dwOfs == ucDIKey) && !(m_didod[i].dwData & 0x80))
			return true;
	}

	//	wasn't pressed.
	return false;
}

///////////////////////////////////////////////////////////////////
//	Return	:	0 if nothing was pressed, otherwise the ascii character 
//				value of the key the user pressed.
//
//	Purpose	:	To get the ascii character value of the key the user typed.
//				So they can enter letters.
char CDIKeyboard::CheckKeys(void)
{	
	//	Get the Current Keyboard State.
	if ( !GetKeyboardState(m_ucAsciiVals) )
		return 0; // Could not GetKeyboardState.

	unsigned short usNum	= 0;
	unsigned int uiVKCode	= 0;

	//	Go through each keyboard key
	for (int i = 0; i < 256; i++)
	{
		// if the high bit is on, it is pressed
		if (KeyDown( (unsigned char)i ))
		{
			//	Map the Scan Code from DirectInput to a Virtual Key value...
			uiVKCode = MapVirtualKeyEx(i, 1, m_keyLayout);
			//	...and translate that Virtual Key into an Ascii Value.
			ToAsciiEx(uiVKCode, i, m_ucAsciiVals, &usNum, 0, m_keyLayout);
		}
	}

	//	Return the Ascii Value.
	return (char)usNum;
}

///////////////////////////////////////////////////////////////////
//	Return	:	0 if nothing was pressed, otherwise the ascii character 
//				value of the key the user pressed.
//
//	Purpose	:	To get the ascii character value of the key the user just typed.
//				So they can enter letters (using DirectInput's Buffered Input).
char CDIKeyboard::CheckBufferedKeysEx(void)
{
	//	Get the Current Keyboard State.
	if (!(GetKeyboardState(m_ucAsciiVals)))
		return 0; // Could not GetKeyboardState.

	unsigned short usNum	= 0;
	unsigned int uiVKCode	= 0;

	//	Go through each element in the Buffer.
	for (DWORD i = 0; i < m_dwBufferElements; i++)
	{
		//	Go through all keys on the keyboard
		for (unsigned int j = 0; j < 256; j++)
		{
			//	If the offset matches the key we are looking for and the high bit is on, it is pressed.
			if ((m_didod[i].dwOfs == j) && (m_didod[i].dwData & 0x80))
			{
				//	Map the Scan Code from DirectInput to a Virtual Key value...
				uiVKCode = MapVirtualKeyEx(m_didod[i].dwOfs, 1, m_keyLayout);
				//	...and translate that Virtual Key into an Ascii Value.
				ToAsciiEx(uiVKCode, m_didod[i].dwOfs, m_ucAsciiVals, &usNum, 0, m_keyLayout);
			}
		}
	}

	//	Return the Ascii Value.
	return (char)usNum;	
}

///////////////////////////////////////////////////////////////////
//	Return	:	0 if nothing was pressed, otherwise the DIK code 
//				of the key the user pressed.
//
//	Purpose	:	To get the DIK code of the key the user is pressing.
//				For key binding.
unsigned char CDIKeyboard::GetDIKCode(void)
{	
	unsigned char ucNum = 0;

	//	Go through each keyboard key
	for (int i = 0; i < 256; i++)
	{
		// find the first one that is pressed
		if (KeyDown( (unsigned char)i ))
		{
			ucNum = (unsigned char)i;
			break;
		}
	}

	//	Return the DIK Code.
	return ucNum;
}

///////////////////////////////////////////////////////////////////
//	Return	:	0 if nothing was pressed, otherwise the DIK code 
//				of the key the user pressed.
//
//	Purpose	:	To get the DIK code of the key the user just pressed.
//				For key binding (using DirectInput's Buffered Input).
unsigned char CDIKeyboard::GetBufferedDIKCodeEx(void)
{
	unsigned char ucNum = 0;

	//	Go through each element in the Buffer.
	for (DWORD i = 0; i < m_dwBufferElements; i++)
	{
		//	Go through all keys on the keyboard
		for (unsigned int j = 0; j < 256; j++)
		{
			//	If the offset matches the key we are looking for and the high bit is on, it is pressed.
			if ((m_didod[i].dwOfs == j) && (m_didod[i].dwData & 0x80))
			{
				ucNum = (unsigned char)j;
				break;
			}
		}
	}

	//	Return the DIK Code.
	return ucNum;	
}

///////////////////////////////////////////////////////////////////////////////////////////
//	CSGD_DIMouse
///////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////
//	Input	:	pDI				-	Pointer to the DirectInput Object.				
//				bIsExclusive	-	Whether or not you want exclusive control of the device.

//	Purpose	:	Setup the mouse for use with DirectInput.
CDIMouse::CDIMouse(LPDIRECTINPUT8 pDI, HWND hWnd, bool bIsExclusive)
{
	//	Create the Mouse Device.
	if (FAILED( pDI->CreateDevice(GUID_SysMouse, &m_lpDevice, NULL) ))
	{
		DIERRBOX(hWnd, "Failed to create Mouse device.")
	}

	//	Set the Data Format for the Mouse.
	if (FAILED( m_lpDevice->SetDataFormat(&c_dfDIMouse2) ))
	{
		DIERRBOX(hWnd, "Failed to set data format on Mouse.")
	}

	//	Set the Cooperative level for the mouse.
	DWORD dwFlags = DISCL_FOREGROUND;

	if (bIsExclusive)
		dwFlags |= DISCL_EXCLUSIVE;
	else
		dwFlags |= DISCL_NONEXCLUSIVE;

	if (FAILED( m_lpDevice->SetCooperativeLevel(hWnd, dwFlags) ))
	{
		DIERRBOX(hWnd, "Failed to set cooperative level on Mouse.")
	}

	//	Set up the device to use buffered input
	//	For Use With Buffered Input.
	DIPROPDWORD dipdw;

	//	Clear the structure to all zeroes.
	memset(&dipdw, 0, sizeof(dipdw));

	dipdw.diph.dwSize       = sizeof(DIPROPDWORD);
	dipdw.diph.dwHeaderSize = sizeof(DIPROPHEADER);
	dipdw.diph.dwObj        = 0;
	dipdw.diph.dwHow        = DIPH_DEVICE;
	dipdw.dwData            = g_knBUFFER_SIZE;	//	Arbitrary buffer size

	//	Set the buffer size on the device.
	if (FAILED( m_lpDevice->SetProperty(DIPROP_BUFFERSIZE, &dipdw.diph) ))
		DIERRBOX(hWnd, "Could not Set the Properties for Buffered Input for Mouse.");

	//	Acquire the Mouse.
	if (FAILED( m_lpDevice->Acquire() ))
	{
		DIERRBOX(hWnd, "Failed to acquire Mouse.")
	}	

	// DIDC_ATTACHED 
	// DIDC_FORCEFEEDBACK
	// DIDC_POLLEDDATAFORMAT VS DIDC_POLLEDDEVICE 
	// dwAxes 
	// dwButtons 
	// dwPOVs 
	DIDEVCAPS  didCaps;

	// clear out struct
	memset(&didCaps, 0, sizeof(didCaps));
	didCaps.dwSize = sizeof(didCaps); 

	//if (SUCCEEDED( m_lpDevice->GetCapabilities(&didCaps) ))
	m_lpDevice->GetCapabilities(&didCaps);
	{
		if (didCaps.dwFlags & DIDC_POLLEDDATAFORMAT)
			int y = 4;
		if (didCaps.dwFlags & DIDC_POLLEDDEVICE)
			int y = 5;
	}

	// will be zero if it failed because the struct was cleared out
	m_nNumButtons = didCaps.dwButtons;

	//	clear out current state
	memset(&m_diMouseState, 0, sizeof(m_diMouseState));
	//	clear prev state
	memset(&m_diPrevMouseState, 0, sizeof(m_diPrevMouseState));

	//	Set psuedo position of mouse
	SetPosX( 0 );
	SetPosY( 0 );
}

///////////////////////////////////////////////////////////////////
//	Return	:	true if it can read the device state, false if it can't.
//	Purpose	:	Reads the state of the device every frame.
bool CDIMouse::ReadDevice(void)
{
	//	Make sure the mouse device was made.
	if (!m_lpDevice)
		return false;

	//	Remember previous state
	memcpy(&m_diPrevMouseState, &m_diMouseState, sizeof(m_diPrevMouseState));

	//	Attempt to read the mouse...
	if (FAILED( m_lpDevice->GetDeviceState(sizeof(m_diMouseState), (LPVOID)&m_diMouseState) ))
	{
		//	If we couldn't, try to re-acquire the device.
		if (FAILED( m_lpDevice->Acquire() ))
			return false; //	Could not re-acquire the Mouse.

		//	Now try reading it
		if (FAILED( m_lpDevice->GetDeviceState(sizeof(m_diMouseState), (LPVOID)&m_diMouseState) ))
			return false;
	}

	// Update "psuedo" position of mouse
	SetPosX( GetPosX() + MovementX() );
	SetPosY( GetPosY() + MovementY() );

	//	Success.
	return true;
}

///////////////////////////////////////////////////////////////////
//	Function:	"ReadBufferedDevice"
//	Return	:	true if it can read the device state, false if it can't.
//	Purpose	:	Gets the DirectInput Buffered Data.
//	NOTE	:	For all Ex functions.
bool CDIMouse::ReadBufferedDevice(void)
{
	//	Make sure the device was made.
	if (!m_lpDevice)
		return false;

	ClearBufferedData();

	//	Attempt to read the device...
	if (FAILED( m_lpDevice->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), m_didod, &m_dwBufferElements, 0) ))
	{
		//	If we couldn't, try to re-acquire the device.
		if (FAILED( m_lpDevice->Acquire() ))
			return false; //	Could not re-acquire the Device.

		ClearBufferedData();

		//	Now try reading it
		if (FAILED( m_lpDevice->GetDeviceData(sizeof(DIDEVICEOBJECTDATA), m_didod, &m_dwBufferElements, 0) ))
			return false;
	}

	//	Success.
	return true;
}

///////////////////////////////////////////////////////////////////
//	Input	:	ucButton	-	The mouse button to check for
//								0 = left, 1 = right, 2 = middle
//	Return	:	true if the mouse button is currently down.
bool CDIMouse::ButtonDown(unsigned char ucButton)
{
	//	if the high bit is on, it is pressed.
	return (m_diMouseState.rgbButtons[ucButton] & 0x80) ? true : false;
}

///////////////////////////////////////////////////////////////////
//	Input	:	ucButton	-	The mouse button to check for 
//								0 = left, 1 = right, 2 = middle
//	Return	:	true if the mouse button was pressed this frame.
//	Purpose	:	To tell if a mouse button was just pressed (without using DirectInput's Buffered Input).
bool CDIMouse::ButtonPressed(unsigned char ucButton)
{
	//	if the button is down and wasn't previously pressed.
	return ButtonDown(ucButton) && !(m_diPrevMouseState.rgbButtons[ucButton] & 0x80);
}

///////////////////////////////////////////////////////////////////
//	Input	:	ucButton	-	The mouse button to check for
//								0 = left, 1 = right, 2 = middle
//	Return	:	true if the mouse button was pressed this frame.
//	Purpose	:	To tell if a mouse button was just pressed (using DirectInput's Buffered Input).
bool CDIMouse::ButtonPressedEx(unsigned char ucButton)
{
	//	Go through each element in the Buffer.
	for (DWORD i = 0; i < m_dwBufferElements; i++)
	{
		//	If the offset matches the button we are looking for and the high bit is on, it is pressed.
		if ((m_didod[i].dwOfs == (DWORD)(DIMOFS_BUTTON0 + ucButton)) && (m_didod[i].dwData & 0x80))
			return true;
	}

	//	wasn't pressed.
	return false;
}

///////////////////////////////////////////////////////////////////
//	Input	:	ucButton	-	The mouse button to check for 
//								0 = left, 1 = right, 2 = middle
//	Return	:	true if the mouse button is currently up.
bool CDIMouse::ButtonUp(unsigned char ucButton)
{
	//	if the high bit is off, it isn't pressed.
	return !ButtonDown(ucButton);
}

///////////////////////////////////////////////////////////////////
//	Input	:	ucButton	-	The mouse button to check for 
//								0 = left, 1 = right, 2 = middle
//	Return	:	true if the mouse button was released this frame.
//	Purpose	:	To tell if a mouse button was just released (without using DirectInput's Buffered Input).
bool CDIMouse::ButtonReleased(unsigned char ucButton)
{
	//	if the button is up and was previously pressed.
	return ButtonUp(ucButton) && (m_diPrevMouseState.rgbButtons[ucButton] & 0x80);
}

///////////////////////////////////////////////////////////////////
//	Input	:	ucButton	-	The mouse button to check for 
//								0 = left, 1 = right, 2 = middle
//	Return	:	true if the mouse button was released this frame.
//	Purpose	:	To tell if a mouse button was just released (using DirectInput's Buffered Input).
bool CDIMouse::ButtonReleasedEx(unsigned char ucButton)
{
	//	Go through each element in the Buffer.
	for (DWORD i = 0; i < m_dwBufferElements; i++)
	{
		//	If the offset matches the button we are looking for and the high bit is off, it was released.
		if ((m_didod[i].dwOfs == (DWORD)(DIMOFS_BUTTON0 + ucButton)) && !(m_didod[i].dwData & 0x80))
			return true;
	}

	//	wasn't pressed.
	return false;
}

///////////////////////////////////////////////////////////////////
//	Return	:	The mouse button that was just pressed.  -1 if there was no button pressed.
//	Purpose	:	To tell if a mouse button was just pressed (without using DirectInput's Buffered Input).

int CDIMouse::CheckBufferedButtons(void)
{
	int nButton = -1;

	//	Go through all mouse buttons.
	for (int j = 0; j < GetNumButtons(); j++)
	{
		//	Find the first button that was pressed
		if (ButtonPressed(j))
		{
			//	return the first one that was found to be pressed.
			nButton = j;
			break;
		}
	}

	//	return the button.
	return nButton;
}

///////////////////////////////////////////////////////////////////
//	Return	:	The mouse button that was just pressed.  -1 if there was no button pressed.
//	Purpose	:	To tell if a mouse button was just pressed (using DirectInput's Buffered Input).
int CDIMouse::CheckBufferedButtonsEx(void)
{
	int nButton = -1;

	//	Go through each element in the Buffer.
	for (DWORD i = 0; i < m_dwBufferElements; i++)
	{
		//	Go through all mouse buttons.
		for (int j = 0; j < GetNumButtons(); j++)
		{
			//	If the offset matches the button we are looking for and the high bit is on, it is pressed.
			if ((m_didod[i].dwOfs == (DWORD)(DIMOFS_BUTTON0 + j)) && (m_didod[i].dwData & 0x80))
			{
				//	return the first one that was found to be pressed.
				nButton = j;
				break;
			}
		}
	}

	//	return the button.
	return nButton;
}

///////////////////////////////////////////////////////////////////
//	Return			:	The amount the mouse has moved this frame.
long CDIMouse::MovementX(void)
{
	return m_diMouseState.lX;
}

///////////////////////////////////////////////////////////////////
//	Return			:	The amount the mouse has moved this frame.

long CDIMouse::MovementY(void)
{
	return m_diMouseState.lY;
}

///////////////////////////////////////////////////////////////////
//	Return			:	The amount the mouse wheel has moved this frame.
//						Positive(+) values mean pushing the wheel away from you.
//						Negative(-) values mean pulling the wheel toward you.
long CDIMouse::WheelMovement(void)
{
	return m_diMouseState.lZ;
}